home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 376-400 / disk_392 / btntape / tape.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  17KB  |  429 lines

  1. /****     BTNtape Handler for SCSI tape drives        ****/
  2. /**** Author: Bob Rethemeyer  (DrBob@cup.portal.com)  ****/
  3.  
  4. #define TVERSION "-BTNTAPE V1.0 RAR-" ## __DATE__
  5.  
  6. /*  (c) Copyright 1990, Robert Rethemeyer.
  7.  *  This software may be freely distributed and redistributed,
  8.  *  for non-commercial purposes, provided this notice is included.
  9.  *-----------------------------------------------------------------------
  10.  *  BTNtape is an AmigaDOS device handler to make a simple DOS TAPE: device.
  11.  *  It converts DOS packets for the device into I/O requests to a
  12.  *  "SCSI-direct" compatible device driver.  It is based on "my.handler"
  13.  *  by Phillip Lindsay and a SCSI-direct program by Robert Mitchell.
  14.  *  Source is ANSI C compliant.  Compile with Lattice v5 or Manx v5.
  15.  *
  16.  *  This handler works in conjunction with the accompanying TapeMon program.
  17.  *----------------------------------------------------------------------------
  18.  * Install this handler in your L: directory.
  19.  * Make a devs:mountlist entry similar to this:
  20.  *
  21.  *   TAPE:  Handler   = L:tape-handler
  22.  *          Stacksize = 4000
  23.  *          Priority  = 5     (use 11 for Supra)
  24.  *          GlobVec   = -1
  25.  *          Startup   = "4/5/8192/1/0/yourscsi.device"
  26.  *                    ( unit/BufMemType/blocksize/Buffers/Reserved/Driver )
  27.  *   #
  28.  * Then use "MOUNT TAPE:" to make the device known to DOS.
  29.  *
  30.  * This handler can circumvent the "write phase" problem in the CBM 2090A
  31.  * driver.  To invoke the circumvention, prefix the name of the driver
  32.  * in the Startup mountlist parameter with a dollar sign ("$").
  33.  * Example:    Startup = "4/5/8192/1/0/$hddisk.device"
  34.  *
  35.  * This handler can circumvent a byte count problem in the Supra v1.10
  36.  * driver.  To invoke the circumvention, prefix the name of the driver
  37.  * in the Startup mountlist parameter with a plus sign ("+").
  38.  * Example:    Startup = "4/5/8192/1/0/+supradirect.device"
  39.  *
  40.  * ----------------------------------------------------------------------------
  41.  */
  42.  
  43. #include <exec/types.h>
  44. #include <exec/nodes.h>
  45. #include <exec/lists.h>
  46. #include <exec/ports.h>
  47. #include <exec/tasks.h>
  48. #include <exec/libraries.h>
  49. #include <exec/io.h>
  50. #include <exec/memory.h>
  51. #include <devices/scsidisk.h>
  52. #include <libraries/dos.h>
  53. #include <libraries/dosextens.h>
  54. #include <libraries/filehandler.h>
  55. #include <stdio.h>
  56. #include <string.h>
  57. #include <ctype.h>
  58. #include <limits.h>
  59.  
  60. #if defined AZTEC_C
  61.   #include <functions.h>
  62. #elif defined LATTICE
  63.   #include <proto/exec.h>
  64. #endif
  65.  
  66. #include "tape.h"
  67. #include "tplink.h"
  68.  
  69. struct things {  /* a collection of things we will have to alloc */
  70.          UBYTE cmdbuff[32];
  71.          UBYTE snsarea[32];
  72.          struct SCSICmd scsicmd;
  73.          UBYTE pad[256];  /* SCSICmd may be larger than include? */
  74.          } ;
  75.  
  76. /*======== Global data */
  77.  
  78. struct IntuitionBase *IntuitionBase;
  79. UBYTE           *cdb;          /* pointer to tape command buffer */
  80. UBYTE           *sns;          /* pointer to sense data buffer   */
  81. struct SCSICmd  *cmd;          /* pointer to scsidirect command  */
  82. struct IOStdReq *ior;          /* pointer to io request structure*/
  83. UBYTE           *TapeBuff[2]   /* pointers to 2 tape buffers     */
  84.                             ={NULL,NULL};
  85. struct tplink   *linktp;       /* pointer to link structure      */
  86. ULONG  blknum;                 /* block number for io operation  */
  87. ULONG  numblks;                /* number of blocks per io operation */
  88. ULONG  rwlen;                  /* bytes in a tape read/write     */
  89. ULONG  bugmask = 0;            /* 2090A bug circumvention        */
  90. long   tpsize;                 /* tape size in blocks            */
  91. short  reserved;               /* number of reserved blocks at BOT */
  92. short  inprog = FALSE;         /* io operation in progress flag  */
  93. char   *z;                     /* scratch                        */
  94. char   dbb[80];                /* buffer for monitor messages    */
  95.  
  96. #define RAWNAME "$$RAWCMD$$"
  97. #define RAWLEN 10
  98.  
  99. /***********************  Main program  ********************************/
  100. #ifdef AZTEC_C
  101.   #pragma intfunc(_main())
  102. #endif
  103. void _main(void)
  104. {
  105.  struct tplink         tpl;         /* structure to link hndlr & mon     */
  106.  struct Process        *myproc;     /* ptr to handler's process struct   */
  107.  struct DosPacket      *mypkt;      /* ptr to dos packet sent            */
  108.  struct DeviceNode     *mynode;     /* ptr to devnode passed in pkt Arg3 */
  109.  ULONG                  dvnode;     /* ptr to devnode passed in pkt Arg3 */
  110.  struct things         *xarea;      /* ptr to dynamic misc. areas        */
  111.  ULONG                 unit;        /* device SCSI unit address          */
  112.  ULONG                 bufmemtype;  /* type of mem for dynamic buffers   */
  113.  ULONG                 blksize;     /* bytes per tape block              */
  114.  ULONG                 TBSize;      /* bytes in a tape buffer            */
  115.  char                  *driver;     /* name of SCSI device driver        */
  116.  UBYTE                 *dptr;       /* ptr to next byte in dos buffer    */
  117.  long                  dcnt;        /* count of dos packet bytes to move */
  118.  long                  mcnt;        /* count of bytes to move            */
  119.  long                  Boff;        /* current offset in tape buffer     */
  120.  long                  rem;         /* bytes remaining in tape buffer    */
  121.  long                  x;           /* scratch                           */
  122.  short                 Bn;          /* current buffer number, 0 or 1     */
  123.  short                 raw;         /* raw command mode flag             */
  124.  short                 rdmode;      /* flag indicating open for reading  */
  125.  short                 norw;        /* no-rewind flag                    */
  126.  short                 open= FALSE; /* tape file open flag               */
  127.  short                 dirty=FALSE; /* buffer has unwritten data in it   */
  128.  BYTE                  acksig;      /* monitor acknowledge signal number */
  129.  
  130. /*======== Startup */
  131.  
  132.  IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
  133.  myproc  = (struct Process *) FindTask(0L);          /* find this process */
  134.  mypkt = taskwait();                           /* wait for startup packet */
  135.  /* packet: Arg1=BSTR to name, Arg2=BSTR to startup string, Arg3=BPTR devnode*/
  136.  mynode = (struct DeviceNode *) BADDR(mypkt->dp_Arg3);
  137.  dvnode = (ULONG) mypkt->dp_Arg3;
  138.  
  139. /*======== Create linkage for the tape monitor:  install pointer to tplink
  140.   ======== structure in the free pointer of the task block, so the tape
  141.   ======== monitor can find it after FindTask().
  142. */
  143.  tpl.keyword = "TapeHandler";
  144.  tpl.version = TVERSION;
  145.  tpl.devnode = (void *)mynode;
  146.  tpl.dbb     = dbb;
  147.  tpl.unit    = &unit;
  148.  linktp = &tpl;
  149.  ((struct Task *)myproc)->tc_UserData = (APTR) linktp;
  150.  
  151. /*======== Extract info from mountlist Startup parameter. It may be
  152.   ======== enclosed in quotes, and each item is separated by a single '/'
  153. */
  154.  z = (char *)BADDR(mypkt->dp_Arg2)+1 ;  /* Arg2= BSTR to mountlist 'Startup'*/
  155.  if(z[0]=='\"')  {                      /* remove quotes if any */
  156.      z++;
  157.      z[strlen(z)-1]= '\0' ;
  158.  }
  159.  unit       = Nextnum(0);
  160.  bufmemtype = Nextnum(1);
  161.  blksize    = Nextnum(1);
  162.  numblks    = Nextnum(1);
  163.  reserved   = Nextnum(1);
  164.  driver     = (char *) Nextnum(-1);
  165.  rwlen = TBSize = numblks * blksize;   /* size of a tape buffer */
  166.  
  167. /*======== Kludges to work around various SCSIdirect driver software problems */
  168.  
  169.  if (driver[0] == '$') {               /* Activate 2090A bug circumvention */
  170.      bugmask = 0x01000000;            /* if driver name starts with '$'   */
  171.      driver++ ;
  172.  }
  173.  else if (driver[0] == '+') {          /* Activate Supra bug circumvention */
  174.      rwlen = 0;                       /* if driver name starts with '+'   */
  175.      driver++ ;
  176.  }
  177.  tpl.driver  = driver;
  178.  
  179. /*======== Allocate some memory for non-data buffers */
  180.  
  181.  if( !(xarea = (struct things *)
  182.            AllocMem(sizeof(struct things), bufmemtype | MEMF_CLEAR) ))
  183.            { returnpkt(mypkt,DOSFALSE,ERROR_NO_FREE_STORE);
  184.              CloseLibrary((struct Library *)IntuitionBase);
  185.              return;
  186.            }
  187.  cdb = &xarea->cmdbuff[0];
  188.  sns = &xarea->snsarea[0];
  189.  cmd = &xarea->scsicmd;
  190.  ior = (struct IOStdReq *) CreateExtIO( CreatePort(0,0),
  191.                                          sizeof(struct IOStdReq));
  192.  
  193. /*======== Open the SCSIdirect device */
  194.  
  195.  if ( OpenDevice(driver,unit,(struct IORequest *)ior,0L)  )  {
  196.     returnpkt(mypkt,DOSFALSE,ERROR_INVALID_COMPONENT_NAME);
  197.     CloseLibrary((struct Library *)IntuitionBase);
  198.     FreeMem(xarea,sizeof(struct things));
  199.     return;
  200.  }
  201.  mynode->dn_Task = &myproc->pr_MsgPort;    /* install handler taskid */
  202.  returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);  /* reply to initial packet */
  203.  
  204. /*======== Allocate the signal that TapeMon will
  205.   ======== use to acknowledge MPR requests.
  206. */
  207.  acksig = AllocSignal(-1);
  208.  if(acksig != -1) tpl.handsig = 1UL << acksig;
  209.  /* else { monitor will not attempt to signal us } */
  210.  
  211.  DoSense(0);
  212.  
  213. /* =========== The main packet processing loop =============== */
  214.  
  215.  for (;;)  {
  216.    mypkt = taskwait();          /* wait for a packet */
  217.    switch(mypkt->dp_Type) {
  218.  
  219.      case ACTION_FINDINPUT:  /*----------- Open() ------------*/
  220.      case ACTION_FINDOUTPUT:
  221.           if(open) returnpkt(mypkt,DOSFALSE,ERROR_OBJECT_IN_USE);
  222.           else {
  223.              TapeBuff[0] = (UBYTE *) AllocMem(TBSize, bufmemtype | MEMF_CLEAR);
  224.              TapeBuff[1] = (UBYTE *) AllocMem(TBSize, bufmemtype | MEMF_CLEAR);
  225.              if (!TapeBuff[0] || !TapeBuff[1]) {
  226.                   FreeStuff(TBSize);
  227.                   returnpkt(mypkt,DOSFALSE,ERROR_NO_FREE_STORE);
  228.                   MPR0("Can't get memory for tape buffers\n")
  229.              }
  230.              else {
  231.                   /* Detect open modes: raw command, continue, goto-block */
  232.                   raw=norw=rdmode=FALSE;
  233.                   for( z=(char *)BADDR(mypkt->dp_Arg3)+1 ; z[0]!=':' ; z++ );
  234.                   if(!memcmp(z+1,RAWNAME,RAWLEN)) raw=norw=TRUE;
  235.                   else if( z[1] == '*' ) norw=TRUE;
  236.                   else if( isdigit((int)z[1]) ) {
  237.                          blknum = (ULONG) strtol(z+1,NULL,0);
  238.                          norw=TRUE;
  239.                          }
  240.  
  241.                   DoSense(0);  /* eat tape-change status */
  242.                   if(norw) x=0;
  243.                   else x=TapeIO(TREWIND,0,CTLWAIT);
  244.                   if(x) {
  245.                      DoSense(x);
  246.                      FreeStuff(TBSize);
  247.                      returnpkt(mypkt,DOSFALSE,ERROR_DEVICE_NOT_MOUNTED);
  248.                   }
  249.                   else {
  250.                      tpsize = TapeIO(RDCAP,0,CTLWAIT) ? /* get tape capacity in sns */
  251.                                 LONG_MAX : ((sns[2] << 8) | sns[3]) + 1;
  252.                      MPR3("%d * %d = %d\n", tpsize,blksize,tpsize*blksize)
  253.                      open=TRUE;
  254.                      dirty=FALSE;
  255.                      inprog=FALSE;
  256.                      Boff=0;
  257.                      Bn=0;
  258.                      rem = TBSize;
  259.                      if(!norw) blknum = reserved;
  260.                      MPR1("Opened at block %d\n",blknum)
  261.                      if (mypkt->dp_Type==ACTION_FINDINPUT)  {
  262.                         rdmode=TRUE;
  263.                         x= TapeIO(TREAD,0,CTLWAIT);      /* fill 1st buffer   */
  264.                         blknum += numblks;
  265.                         if(!x) x=TapeIO(TREAD,1,CTLIMM); /* start reading 2nd */
  266.                      }
  267.                      returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);
  268.                   }
  269.              }
  270.           }
  271.           break;
  272.  
  273.      case ACTION_END:        /*----------- Close() -----------*/
  274.           if(open) {
  275.             if(dirty) {
  276.                if(raw) TapeIO(RAWCMD,Bn,CTLWAIT);  /* send user command */
  277.                else    TapeIO(TWRITE,Bn,CTLWAIT);  /* write last block */
  278.             }
  279.             else if(inprog) TapeIO(TFINISH,0,CTLWAIT); /* wait for last one */
  280.             open=FALSE;
  281.             FreeStuff(TBSize);
  282.           }
  283.           returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);
  284.           if(!rdmode) blknum += numblks;
  285.           MPR1("Closed at block %d\n",blknum)
  286.           break;
  287.  
  288.      case ACTION_READ:       /*----------- Read() ------------*/
  289.           if(x) {
  290.               DoSense(x);
  291.               mypkt->dp_Arg3 = -1;
  292.               goto RDERR;
  293.           }
  294.           dptr = (UBYTE *) mypkt->dp_Arg2;
  295.           dcnt =           mypkt->dp_Arg3;
  296.           while(dcnt)   {
  297.             if(!rem)     {
  298.                blknum += numblks;   /* start reading next buffer */
  299.                if(x=TapeIO(TREAD,Bn,CTLIMM))  {
  300.                    DoSense(x);
  301.                    mypkt->dp_Arg3 = -1;
  302.                    goto RDERR;
  303.                }
  304.                Bn ^= 1;             /* switch to other (filled) buffer */
  305.                rem = TBSize;
  306.                Boff = 0;
  307.             }
  308.             mcnt = (dcnt>rem) ? rem : dcnt;
  309.             memcpy (dptr, &TapeBuff[Bn][Boff], mcnt);
  310.             dcnt -= mcnt ;
  311.             Boff += mcnt ;
  312.             rem  -= mcnt ;
  313.             dptr += mcnt ;
  314.           }
  315.           RDERR:
  316.           returnpkt(mypkt,mypkt->dp_Arg3,mypkt->dp_Arg2);
  317.           break;
  318.  
  319.      case ACTION_WRITE:      /*----------- Write() -----------*/
  320.           dptr = (UBYTE *) mypkt->dp_Arg2;
  321.           dcnt =           mypkt->dp_Arg3;
  322.           while (dcnt)    {
  323.             if (dcnt >= rem) {
  324.                memcpy (&TapeBuff[Bn][Boff], dptr, rem);
  325.                if( x=TapeIO(TWRITE,Bn,CTLIMM) ) {
  326.                        DoSense(x);
  327.                        mypkt->dp_Arg3 = -1;
  328.                        goto WRTERR;
  329.                }
  330.                blknum += numblks;
  331.                dcnt -= rem;
  332.                dptr += rem;
  333.                Boff  = 0;
  334.                rem   = TBSize;
  335.                Bn   ^= 1;
  336.                dirty = FALSE;
  337.             }
  338.             else {
  339.                memcpy (&TapeBuff[Bn][Boff], dptr, dcnt);
  340.                rem  -= dcnt;
  341.                Boff += dcnt;
  342.                dcnt  = 0;
  343.                dirty = TRUE;
  344.             }
  345.           }
  346.           WRTERR:
  347.           returnpkt(mypkt,mypkt->dp_Arg3,mypkt->dp_Res2);
  348.           break;
  349.  
  350.      case ACTION_CURRENT_VOLUME:
  351.           returnpkt(mypkt,dvnode,DOSFALSE);
  352.           break;
  353.  
  354.      case ACTION_LOCATE_OBJECT:  /* lock */
  355.           returnpkt(mypkt,mypkt->dp_Arg1,mypkt->dp_Res2);
  356.           break;
  357.  
  358.      case ACTION_FREE_LOCK:      /* unlock */
  359.           returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);
  360.           break;
  361.  
  362.      default:    /* say what? */
  363.           returnpkt(mypkt,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  364.           MPR1("Unsupported_Pkt=%d\n",mypkt->dp_Type)
  365.  
  366.      } /* end of switch */
  367.  } /* end of loop */
  368. } /* end of _main() */
  369.  
  370. /**************************************************************************/
  371.  
  372. void DoSense(long x)
  373. {
  374.    sns[2] = sns[12] = 0;
  375.    x=x>>8;
  376.    if(x==0) TapeIO(TSENSE,0,CTLWAIT);
  377.    else if(x==HFERR_BadStatus)  {
  378.        TapeIO(TSENSE,0,CTLWAIT);
  379.        if(!(sns[0] & 0x70)) sns[2]=sns[0] & 0x0f; /* non-extended sense */
  380.        linktp->sense = sns[2];    /* keep last error info */
  381.        linktp->xsense = sns[12];
  382.    }
  383.    MPR3("io_Error=%d  Sense=%X,%02X\n", x, sns[2], sns[12])
  384.    return;
  385. }
  386.  
  387. /**************************************************************************/
  388.  
  389. void FreeStuff(ULONG bs)
  390. {
  391.    if(inprog) TapeIO(TFINISH,0,CTLWAIT); /* just in case */
  392.    if(TapeBuff[0]) FreeMem(TapeBuff[0],bs);
  393.    if(TapeBuff[1]) FreeMem(TapeBuff[1],bs);
  394.    TapeBuff[0] = TapeBuff[1] = NULL;
  395.    return;
  396. }
  397.  
  398. /**************************************************************************/
  399. /* Nextnum parses and returns the next number in the startup string */
  400.  
  401. ULONG Nextnum(short kk)            /* kk=0 for first number */
  402. {                                  /* kk=1 for other numbers */
  403. char *zz;                          /* kk=-1 for pointer to last token */
  404.    zz = (kk) ? NULL : z;
  405.    z = strtok(zz,"/");
  406.    if(kk==-1) return( (ULONG) z);
  407.    else       return( (ULONG) strtol(z,NULL,0) );
  408. }
  409.  
  410. /**************************************************************************
  411.    MonPrint requests that the TapeMon program print the message in 'dbb'.
  412.     Since this handler cannot do DOS I/O, it must beg the TapeMon program,
  413.     possibly running in a CLI somewhere, to do the printf for it.  If the
  414.     TapeMon is running, it will have installed a pointer to its task in
  415.     the link structure, and we can Signal() it.
  416. */
  417.  
  418. void MonPrint(void)
  419. {
  420.    if(linktp->montask)  {
  421.       Signal(linktp->montask, linktp->monsig);
  422.       Wait  (linktp->handsig);
  423.       Signal(linktp->montask, linktp->monsig);
  424.       Wait  (linktp->handsig);
  425.    }
  426.    return;
  427. }
  428.  
  429.